package springintegrationsample.runner;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.springframework.core.serializer.Deserializer;
import org.springframework.core.serializer.Serializer;

import com.hundsun.fasp.trans.fix.base.FixData;
import com.hundsun.fasp.trans.fix.base.HsFix;
import com.hundsun.fasp.trans.fix.base.util.DataSet2Fix;
import com.hundsun.fasp.trans.fix.base.util.FixAnalyzer;
import com.hundsun.fasp.trans.fix.base.util.FixUtil;

public class BlankDes implements Serializer<FixData>, Deserializer<FixData> {
	private static final String NOT_NEED_ENCRYP = "F";
	private static final String NEED_ENCRYP = "T";
	private static int HEAD_LENGTH_BYTES_LENGTH = 3;
	private static int CHARSET_LENGTH = 8;
	private static String charset = "GBK";
	private static Encrypter encrypter;
	private static boolean IS_NEED_ENCRYP = false;
	
	@Override
	public FixData deserialize(InputStream inputStream) throws IOException {
		FixData analyzerMakeFix = new FixData();
		analyzerMakeFix = parse(inputStream);
		return analyzerMakeFix;
	}
	
	private static int parseOrderNumber(InputStream inputStream,int length) throws IOException {
		String value = parseString(inputStream, length);
		return Integer.valueOf(value.toString());
	}
	
	private static String parseString(InputStream inputStream, int length) throws IOException {
		StringBuilder builder = new StringBuilder();
		int c;
		for (int i = 0; i < length; ++i) {
			c = inputStream.read();
			checkClosure(c);
			builder.append((char)c);
		}

		return builder.toString();
	}

	protected static void checkClosure(int bite) throws IOException {
		if (bite < 0) {
			throw new IOException("Socket closed during message assembly");
		}
	}
	
	public static FixData parse(InputStream inputStream) throws IOException {
		
		int c = inputStream.read();
		boolean encryp = false;
		if(NEED_ENCRYP.toCharArray()[0]==(char)c){
			encryp = true;
		}
		int headLength  = parseOrderNumber(inputStream,HEAD_LENGTH_BYTES_LENGTH);//4位
		if (headLength < 9) {
			throw new RuntimeException("报文太短");
		}
		int contentLength =  parseOrderNumber(inputStream,5);//5位
		
		if (headLength >= 17) {
			charset = parseString(inputStream, headLength-9);
		}
		if (charset.equals("") || (!charset.equals("GBK") && !charset.equals("UTF-8") && !charset.equals("GB18030"))) {
			charset = "GBK";
		}
		byte[] contentBytes = new byte[contentLength];
		inputStream.read(contentBytes, 0, contentLength);
		byte[] contentPack = contentBytes;
		if(encryp){
			System.out.println("-----------------------");
			System.out.print("encryp:");
			System.out.println(encryp);
			System.out.println("-----------------------");
			contentPack =  getEncrypter().decrypt(contentPack);
		}
		FixData analyzerMakeFix = FixAnalyzer.analyzerMakeFix(contentPack, charset);
		return analyzerMakeFix;
	}

	@Override
	public void serialize(FixData fixData, OutputStream outputStream) throws IOException {
		byte[] pack = make(fixData);
		outputStream.write(pack);
		outputStream.flush();
	}

	public static byte[] make(FixData fixData) throws IOException {
		HsFix fix = DataSet2Fix.data2Fix(fixData);
		byte[] content = fix.toString().getBytes(charset);
		String encrpyTag = NEED_ENCRYP;
		if(!isNeedEncrypter()){
			encrpyTag = NOT_NEED_ENCRYP;
		}else{
			content =  getEncrypter().encrypt(content);
		}
		int headLength = 1 + 3 + 5 + ((charset.equals("GBK") || charset.equals("GB18030")) ? 0 : CHARSET_LENGTH);
		byte[] pack = new byte[headLength + content.length];
		System.arraycopy((encrpyTag + FixUtil.fix0BeforeString(String.valueOf(headLength), 3)
				+ FixUtil.fix0BeforeString(String.valueOf(content.length), 5)
				+ ((charset.equals("GBK") || charset.equals("GB18030")) ? ""
						: (FixUtil.fixSpaceAfterString(charset, 8)))).getBytes(),
				0, pack, 0, headLength);
		System.arraycopy(content, 0, pack, headLength, content.length);

		return pack;

	}
	
	public static void setEncrypter(Encrypter encrypterVar){
		encrypter = encrypterVar;
	}
	
	public static Encrypter getEncrypter() {
		return encrypter;
	}
	public static boolean isNeedEncrypter(){
		return IS_NEED_ENCRYP;
	}
	public static void setNeedEncrypter(boolean var){
		IS_NEED_ENCRYP = var;
	}
}

